﻿using Sasa.QualityTools.CodeAnalysis.SearchEngine.Processing.Tokens;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Sasa.QualityTools.CodeAnalysis.SearchEngine.Processing
{
    internal class Preprocessor
    {
        internal IEnumerable<IToken> Process(IEnumerable<IToken> tokens)
        {
            return ComplementAbbrevedTokens(ComplementParentheses(tokens));
        }

        private IEnumerable<IToken> ComplementParentheses(IEnumerable<IToken> tokens)
        {
            if (tokens == null || tokens.Count() == 0)
            {
                return new List<IToken>();
            }

            List<IToken> result = new List<IToken>();

            int nest = 0;
            for (int i = 0; i < tokens.Count(); i++)
            {
                IToken token = tokens.ElementAt(i);
                result.Add(token);
                if (token is LPar)
                {
                    nest++;
                }
                else if (token is RPar)
                {
                    if (nest == 0)
                    {
                        result.Insert(0, new LPar { Value = "(" });
                    }
                    else
                    {
                        nest--;
                    }
                }
            }

            for (int i = 0; i < nest; i++)
            {
                result.Add(new RPar { Value = ")" });
            }

            return result;
        }

        private IEnumerable<IToken> ComplementAbbrevedTokens(IEnumerable<IToken> tokens)
        {
            if (tokens == null || tokens.Count() == 0)
            {
                return new List<IToken>();
            }

            List<IToken> result = new List<IToken>();

            IToken left = null;
            IToken right = null;
            int count = tokens.Count();
            for (int i = 0; i < count + 1; i++)
            {
                left = right;
                right = (i <= count - 1) ? tokens.ElementAt(i) : null;
                if (ShouldComplementAnd(left, right))
                {
                    result.Add(new And { Value = "AND" });
                }
                else if (ShouldComplementWord(left, right))
                {
                    result.Add(new Word { Value = "" });
                }

                if (right != null)
                {
                    result.Add(right);
                }
            }

            return result;
        }

        private bool ShouldComplementWord(IToken left, IToken right)
        {
            if (left == null && right is IOperatorToken)
            {
                return true;
            }
            else if (left is IOperatorToken && right == null)
            {
                return true;
            }
            else
            {
                return (left is IOperatorToken || left is LPar) && (right is IOperatorToken || right is RPar);
            }
        }

        private bool ShouldComplementAnd(IToken left, IToken right)
        {
            return (left is Word || left is RPar) && (right is Word || right is LPar);
        }
    }
}
